/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.xeerkat.xmpp.server.www;

import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.logging.Level;
import org.infoset.xml.Document;
import org.infoset.xml.DocumentLoader;
import org.infoset.xml.Element;
import org.infoset.xml.InfosetFactory;
import org.infoset.xml.ItemConstructor;
import org.infoset.xml.ItemDestination;
import org.infoset.xml.XMLException;
import org.infoset.xml.sax.SAXDocumentLoader;
import org.infoset.xml.util.WriterItemDestination;
import org.restlet.data.CharacterSet;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.OutputRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;
import org.xeerkat.xmpp.ID;
import org.xeerkat.xmpp.server.XMPPServer;
import org.xeerkat.xmpp.server.db.Contact;
import org.xeerkat.xmpp.server.db.User;

/**
 *
 * @author alex
 */
public class UserRosterResource extends ServerResource {

   public UserRosterResource()
   {
      setNegotiated(false);
   }
   
   public Representation get() {
      XMPPServer server = (XMPPServer)getContext().getAttributes().get("xmpp.server");
      try {
         String id = getRequest().getAttributes().get("id").toString();
         final User user = server.getDatabase().getUser(new ID(id));
         if (user==null) {
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return null;
         }
         Representation rep = new OutputRepresentation(MediaType.APPLICATION_XML) {
            public void write(OutputStream os)
               throws IOException
            {
               Writer w = new OutputStreamWriter(os,getCharacterSet().toString());
               ItemDestination dest = new WriterItemDestination(w,getCharacterSet().toString());
               ItemConstructor constructor = InfosetFactory.getDefaultInfoset().createItemConstructor();
               try {
                  dest.send(constructor.createDocument());
                  Element rosterE = constructor.createElement(AdminApplication.ROSTER);
                  rosterE.setAttributeValue("id", user.getXMPPId().toString());
                  dest.send(rosterE);
                  try {
                     Iterator<Contact> contacts = user.getContacts();
                     while (contacts.hasNext()) {
                        Contact contact = contacts.next();
                        Element contactE = constructor.createElement(AdminApplication.CONTACT);
                        contactE.setAttributeValue("id",contact.getXMPPID().toString());
                        String name = contact.getName();
                        if (name!=null) {
                           contactE.setAttributeValue("name",name);
                        }
                        contactE.setAttributeValue("subscription",contact.getSubscription().toString().toLowerCase());
                        contactE.setAttributeValue("ask",contact.getAsk().toString().toLowerCase());
                        dest.send(contactE);
                        Iterator<String> groups = contact.getGroupNames();
                        while (groups.hasNext()) {
                           dest.send(constructor.createElement(AdminApplication.GROUP));
                           dest.send(constructor.createCharacters(groups.next()));
                           dest.send(constructor.createElementEnd(AdminApplication.GROUP));
                        }
                        dest.send(constructor.createElementEnd(AdminApplication.RESOURCE));
                     }
                  } catch (SQLException ex) {
                     getLogger().log(Level.SEVERE,"Cannot get resources for user "+user.getXMPPId(),ex);
                  }
                  dest.send(constructor.createElementEnd(AdminApplication.ROSTER));
                  dest.send(constructor.createDocumentEnd());
               } catch (XMLException ex) {
                  throw new IOException(ex.getMessage());
               }
               w.flush();
            }
         };
         rep.setCharacterSet(CharacterSet.UTF_8);
         setStatus(Status.SUCCESS_OK);
         return rep;
      } catch (SQLException ex) {
         getLogger().log(Level.SEVERE,"Cannot get users from database.",ex);
         setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Database error.");
      }
   }
   
   public boolean allowPost() {
      return true;
   }
   
   public Representation post(Representation entity) {
      XMPPServer server = (XMPPServer)getContext().getAttributes().get("xmpp.server");
      try {
         String id = getRequest().getAttributes().get("id").toString();
         final User user = server.getDatabase().getUser(new ID(id));
         if (user==null) {
            setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return null;
         }
         Reader r = entity.getReader();
         DocumentLoader loader = new SAXDocumentLoader();
         Document doc = loader.load(r);
         Element top = doc.getDocumentElement();
         if (!top.getName().equals(AdminApplication.CONTACT)) {
            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("Element "+top.getName()+" not allowed.");
         }
         String idS = top.getAttributeValue("id");
         if (idS==null) {
            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("Missing 'id' attribute.");
         }
         ID contactId = new ID(idS);
         
         String name = top.getAttributeValue("name");
         String svalue = top.getAttributeValue("subscription");
         if (svalue==null) {
            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("Missing 'subscription' attribute.");
         }
         Contact.Subscription subscription = null;
         try {
            subscription = Contact.Subscription.fromString(svalue);
         } catch (IllegalArgumentException ex) {
            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation(ex.getMessage());
         }
         String avalue = top.getAttributeValue("ask");
         if (avalue==null) {
            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("Missing 'ask' attribute.");
         }
         Contact.Ask ask = null;
         try {
            ask = Contact.Ask.fromString(avalue);
         } catch (IllegalArgumentException ex) {
            setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation(ex.getMessage());
         }

         Contact contact = user.getContact(contactId);
         if (contact==null) {
            contact = user.addContact(contactId);
         }            
         contact.setAsk(ask);
         contact.setName(name);
         contact.setSubscription(subscription);
         contact.update();
         setStatus(Status.SUCCESS_NO_CONTENT);
         return null;
      } catch (IOException ex) {
         getLogger().log(Level.SEVERE,"I/O error during processing.",ex);
         return new StringRepresentation("I/O error during processing.");
      } catch (SQLException ex) {
         getLogger().log(Level.SEVERE,"Cannot create user in database.",ex);
         setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Database error.");
      } catch (XMLException ex) {
         setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation(ex.getMessage());
      }
   }
}
